package burubaka.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;
import org.slim3.datastore.Datastore;

import burubaka.BurubakaConstants;
import burubaka.meta.BetTemplateBodyMeta;
import burubaka.meta.BetTemplateMeta;
import burubaka.model.BetTemplate;
import burubaka.model.BetTemplateBody;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;

public class BetTemplateService {
	private static final Logger log = Logger.getLogger(BetTemplateService.class.getName());

	private BetTemplateMeta meta = new BetTemplateMeta();
	private BetTemplateBodyMeta bodyMeta = new BetTemplateBodyMeta();

	/**
	 * キーからBetTemplateを取得する
	 * 
	 * @param key
	 * @return BetTemplate
	 */
	public BetTemplate findBetTemplateByKey(Key key) {
		// return Datastore.get(BetTemplate.class, key);
		return Datastore.query(this.meta, key).asSingle();
	}

	/**
	 * 先祖キーからBetTemplateを取得する
	 * 
	 * @param andKey
	 * @return BetTemplate
	 */
	public BetTemplate findBetTemplateKeyByAncKey(Key ancKey) {
		return Datastore.query(this.meta, ancKey).asSingle();
	}

	/**
	 * 先祖キーからBetTemplateBodyの一覧を取得する
	 * 
	 * @param key
	 * @return List<BetTemplateBody>
	 */
	public List<BetTemplateBody> findBetTemplateBodyByAncKey(Key ancKey) {
		if (ancKey == null) {
			return new ArrayList<BetTemplateBody>();
		}

		List<BetTemplateBody> ret = Datastore.query(this.bodyMeta, ancKey).asList();
		Collections.sort(ret, new Comparator<BetTemplateBody>() {
			@Override
			public int compare(BetTemplateBody o1, BetTemplateBody o2) {
				int ret = 0;
				if (StringUtils.isNotEmpty(o1.getBetClass()) && StringUtils.isNotEmpty(o2.getBetClass())) {
					Integer betClass1 = Integer.valueOf(o1.getBetClass());
					Integer betClass2 = Integer.valueOf(o2.getBetClass());
					ret = betClass1.compareTo(betClass2);
					if (ret != 0) {
						return ret;
					}
				}

				Integer mark1 = null;
				Integer mark2 = null;
				if (StringUtils.isNotEmpty(o1.getMark1()) && StringUtils.isNotEmpty(o2.getMark1())) {
					mark1 = Integer.valueOf(o1.getMark1());
					mark2 = Integer.valueOf(o2.getMark1());
					ret = mark1.compareTo(mark2);
					if (ret != 0) {
						return ret;
					}
				}

				if (StringUtils.isNotEmpty(o1.getMark2()) && StringUtils.isNotEmpty(o2.getMark2())) {
					mark1 = Integer.valueOf(o1.getMark2());
					mark2 = Integer.valueOf(o2.getMark2());
					ret = mark1.compareTo(mark2);
					if (ret != 0) {
						return ret;
					}
				}

				if (StringUtils.isNotEmpty(o1.getMark3()) && StringUtils.isNotEmpty(o2.getMark3())) {
					mark1 = Integer.valueOf(o1.getMark3());
					mark2 = Integer.valueOf(o2.getMark3());
					ret = mark1.compareTo(mark2);
				}

				return ret;
			}
		});

		return ret;
		// return Datastore
		// .query(this.bodyMeta, ancKey)
		// .sort(this.bodyMeta.betClass.asc, this.bodyMeta.mark1.asc,
		// this.bodyMeta.mark2.asc,
		// this.bodyMeta.mark3.asc).asList();
	}

	/**
	 * デフォルトBetTemplateBodyを取得する
	 * 
	 * @param key
	 * @return List<BetTemplateBody>
	 */
	public BetTemplate getDefaultBetTemplate() {
		return Datastore.query(this.meta).filter(this.meta.defaultFlag.equal(BurubakaConstants.FLAG_ON)).asSingle();
	}

	/**
	 * 先祖キーからBetTemplateBodyのキー一覧を取得する
	 * 
	 * @param key
	 * @return List<BetTemplateBody>
	 */
	public List<Key> findBetTemplateBodyKeyByAncKey(Key ancKey) {
		return Datastore.query(this.bodyMeta, ancKey).asKeyList();
	}

	/**
	 * 登録
	 * 
	 * @param model
	 * @return RaceInfo
	 */
	public BetTemplate regist(BetTemplate model) {
		Transaction tx = Datastore.beginTransaction();
		Datastore.put(model);
		tx.commit();
		return model;
	}

	/**
	 * 登録
	 * 
	 * @param model
	 * @param list
	 * @param tipsterKey
	 * @return RaceInfo
	 */
	public BetTemplate regist(BetTemplate model, List<BetTemplateBody> list, Key tipsterKey) {

		Transaction tx = Datastore.beginTransaction();
		BetTemplate betTemplate = findBetTemplateByKey(tipsterKey);
		Key childKey = null;
		if (betTemplate == null) {
			childKey = Datastore.allocateId(tipsterKey, BetTemplate.class);
		} else {
			childKey = betTemplate.getKey();
		}
		model.setKey(childKey);
		if (StringUtils.isEmpty(model.getName())) {
			model.setName(betTemplate.getName());
		}

		BetTemplate ret = registBetTemplate(model, list);

		tx.commit();
		return ret;
	}

	/**
	 * 登録
	 * 
	 * @param model
	 * @param list
	 * @param tipsterKey
	 * @return RaceInfo
	 */
	public BetTemplate regist(BetTemplate model, List<BetTemplateBody> list) {

		Transaction tx = Datastore.beginTransaction();
		BetTemplate ret = registBetTemplate(model, list);
		tx.commit();

		return ret;
	}

	/**
	 * 登録
	 * 
	 * @param model
	 * @param list
	 * @param tipsterKey
	 * @return RaceInfo
	 */
	private BetTemplate registBetTemplate(BetTemplate model, List<BetTemplateBody> list) {

		Datastore.put(model);
		List<Key> bodyKeyList = findBetTemplateBodyKeyByAncKey(model.getKey());
		Datastore.delete(bodyKeyList);

		for (BetTemplateBody body : list) {
			Key grandsonKey = Datastore.allocateId(model.getKey(), BetTemplateBody.class);
			body.setKey(grandsonKey);
			String betClass = body.getBetClass();
			if (BurubakaConstants.BET_CLASS_WIN[0].equals(betClass)
					|| BurubakaConstants.BET_CLASS_PLACE[0].equals(betClass)) {
				body.setMark2("");
				body.setMark3("");
			} else if (!BurubakaConstants.BET_CLASS_TRIO[0].equals(betClass)
					&& !BurubakaConstants.BET_CLASS_TRIFECTA[0].equals(betClass)) {
				body.setMark3("");
			}
		}

		Datastore.put(list);

		return model;
	}

	/**
	 * テンプレート設定
	 * 
	 * @param resMap
	 * @param markSheetList
	 */
	public void setBetTemplateBody(Map<String, Object> resMap, List<BetTemplateBody> betTemplateBodyL) {
		List<BetTemplateBody> quinellaList = new ArrayList<BetTemplateBody>();
		List<BetTemplateBody> exactaList = new ArrayList<BetTemplateBody>();
		List<BetTemplateBody> trioList = new ArrayList<BetTemplateBody>();
		List<BetTemplateBody> trifectaList = new ArrayList<BetTemplateBody>();
		for (BetTemplateBody tempBody : betTemplateBodyL) {
			if (BurubakaConstants.BET_CLASS_QUINELLA[0].equals(tempBody.getBetClass())) {
				quinellaList.add(tempBody);
			}
			if (BurubakaConstants.BET_CLASS_EXACTA[0].equals(tempBody.getBetClass())) {
				exactaList.add(tempBody);
			}
			if (BurubakaConstants.BET_CLASS_TRIO[0].equals(tempBody.getBetClass())) {
				trioList.add(tempBody);
			}
			if (BurubakaConstants.BET_CLASS_TRIFECTA[0].equals(tempBody.getBetClass())) {
				trifectaList.add(tempBody);
			}
		}
		resMap.put("quinella", quinellaList);
		resMap.put("exacta", exactaList);
		resMap.put("trio", trioList);
		resMap.put("trifecta", trifectaList);
	}

}
